from PySide6.QtCore import QObject, Signal
from threading import Lock


class EventBus(QObject):
    """全局事件总线"""

    event = Signal(str, object)

    log_message = Signal(str) # 全局日志
    error_message = Signal(str)
    dialog_message = Signal(dict)

    _instance = None
    _lock = Lock()

    def __new__(cls):
        with cls._lock:
            if cls._instance is None:
                cls._instance = super().__new__(cls)
                cls._instance._initialized = False
            return cls._instance


    def __init__(self):
        if getattr(self, "_initialized", False):
            return
        super().__init__()
        self._routes = {}
        self._initialized = True

    # ---------- 注册 ----------
    def on(self, event_name: str, callback):
        if not callable(callback):
            return

        def wrapper(name, payload):
            if name == event_name:
                callback(payload)

        self._routes.setdefault(event_name, set()).add(wrapper)
        self.event.connect(wrapper)

    # ---------- 解绑 ----------
    def off(self, event_name: str, callback=None):
        wrappers = self._routes.get(event_name, set())
        if not wrappers:
            return

        if callback is None:
            for w in list(wrappers):
                try:
                    self.event.disconnect(w)
                except Exception:
                    pass
            wrappers.clear()

    # ---------- 发射 ----------
    def emit(self, event_name: str, data=None):
        self.event.emit(event_name, data)

    # ---------- 自动解绑 ----------
    def bind(self, event_name: str, callback):
        if not callable(callback):
            return lambda: None

        def wrapper(name, payload):
            if name == event_name:
                callback(payload)

        self._routes.setdefault(event_name, set()).add(wrapper)
        self.event.connect(wrapper)

        def off_handle():
            try:
                self.event.disconnect(wrapper)
            except Exception:
                pass
            self._routes[event_name].discard(wrapper)

        return off_handle
